package microservice

import (
	"log"
	"net"
	"errors"
	"strconv"
	"flag"
	"math/rand"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"

	"change.tm/finder"
)

func CreateServer() *grpc.Server {
	var s *grpc.Server = grpc.NewServer()
	return s
}

func CreateSimpleClient(name string) (*grpc.ClientConn, error) {
	if(name==""){
		return nil, errors.New("未提供服务名称")
	}
	address, port, err := finder.GetService(name)
	if err != nil {
		log.Fatalf("[ Error ] - 无法连接到客户端")
	}
	connection, err := grpc.Dial(address+":"+port, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("[ Error ] - 无法连接到客户端")
	}
	return connection, nil
}

func Register(name string, server *grpc.Server){
	var ip = []string {}
	var port string

	uip := flag.String("ip", "", "自定义监听IP")
	uport := flag.String("port", "", "自定义端口号")
	flag.Parse()

	if *uip == "" {
		var err error
		ip, err = getIPAddress()
		if err != nil {
			log.Fatalf("[ ERROR ] - 无法获取ip地址 : %v", err)
		}
	} else {
		ip = append(ip, *uip)
	}

	if *uport == "" {
		var err error
		port, err = getPort();
		if err != nil {
			log.Fatalf("[ ERROR ] - 无法获取可用端口 : %v", err)
		}
	} else {
		port = *uport
	}

	lis, err := net.Listen("tcp", ":" + port)
	if err != nil {
		log.Fatalf("[ ERROR ] - 无法监听端口 %s : %v", port ,err)
	}

	reflection.Register(server)

	go finder.Register(name, ip, port)
	
	if err := server.Serve(lis); err != nil {
		// 启动服务
		log.Fatalf("[ ERROR ] - 无法启动服务 : %v", err)
	}	

}

func getIPAddress() ([]string, error) {
	// 遍历网卡获取本机可用IP地址
    addrs, err := net.InterfaceAddrs()

    if err != nil {
        return nil, err
    }

    result := []string {}

    for _, address := range addrs {
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
        		result = append(result, ipnet.IP.String())
            }
        }
	}

    return result,nil
}

func getPort() (string, error) {
	// 获取可用端口
	port := 3000

	onpro := true
	for onpro {
		con, err := net.Listen("tcp",":" + strconv.Itoa(port));
		if err != nil {
			port += rand.Intn(49)+1
		} else {
			onpro = false;
			con.Close()
		}
	}

	return strconv.Itoa(port),nil
}